using System.Windows.Media;
using System.Windows.Media.Media3D;

namespace Sensor.UI.PointClouds;

/// <summary>
/// 箭头工厂类，用于创建3D箭头模型
/// </summary>
public static class ArrowFactory
{
    #region 公共方法
    /// <summary>
    /// 创建3D箭头模型
    /// </summary>
    /// <param name="startPoint">箭头起点</param>
    /// <param name="direction">箭头方向向量</param>
    /// <param name="size">箭头整体大小</param>
    /// <param name="diameter">箭头直径，默认为0.2</param>
    /// <param name="headLengthRatio">箭头头部长度比例，默认为0.3</param>
    /// <param name="color">箭头颜色，默认为红色</param>
    /// <returns>箭头模型</returns>
    public static Model3D CreateArrow(
        Point3D startPoint, 
        Vector3D direction, 
        double size, 
        double diameter = 0.2, 
        double headLengthRatio = 0.3, 
        Color color = default)
    {
        ArgumentNullException.ThrowIfNull(startPoint);
        ArgumentNullException.ThrowIfNull(direction);
        
        // 如果未指定颜色，使用红色
        if (color == default)
            color = Colors.Red;

        // 确保方向向量是单位向量
        direction.Normalize();
        
        // 计算箭头头部和杆部的长度
        double headLength = size * headLengthRatio;
        double shaftLength = size - headLength;
        
        // 创建箭头模型组
        var arrowGroup = new Model3DGroup();
        
        // 创建箭头杆部（圆柱体）
        var shaft = CreateCylinder(startPoint, direction, shaftLength, diameter, color);
        arrowGroup.Children.Add(shaft);
        
        // 计算箭头头部起点
        var headStartPoint = startPoint + direction * shaftLength;
        
        // 创建箭头头部（圆锥体）
        var head = CreateCone(headStartPoint, direction, headLength, diameter * 1.5, color);
        arrowGroup.Children.Add(head);
        
        return arrowGroup;
    }
    #endregion

    #region 私有方法
    /// <summary>
    /// 创建圆柱体模型
    /// </summary>
    /// <param name="startPoint">圆柱体起点</param>
    /// <param name="direction">圆柱体方向向量</param>
    /// <param name="length">圆柱体长度</param>
    /// <param name="diameter">圆柱体直径</param>
    /// <param name="color">圆柱体颜色</param>
    /// <returns>圆柱体模型</returns>
    private static GeometryModel3D CreateCylinder(
        Point3D startPoint, 
        Vector3D direction, 
        double length, 
        double diameter, 
        Color color)
    {
        ArgumentNullException.ThrowIfNull(startPoint);
        ArgumentNullException.ThrowIfNull(direction);
        // 创建圆柱体的几何体
        var mesh = new MeshGeometry3D();
        
        // 圆柱体的分段数
        int segments = 16;
        double radius = diameter / 2;
        
        // 计算圆柱体的端点
        var endPoint = startPoint + direction * length;
        
        // 创建垂直于圆柱体方向的向量
        Vector3D perpendicular1, perpendicular2;
        
        // 如果方向向量接近Y轴，使用Z轴作为参考
        if (Math.Abs(direction.Y) > 0.9)
        {
            perpendicular1 = new Vector3D(1, 0, 0);
        }
        else
        {
            perpendicular1 = new Vector3D(0, 1, 0);
        }
        
        // 计算两个垂直向量
        perpendicular1 = Vector3D.CrossProduct(direction, perpendicular1);
        perpendicular1.Normalize();
        perpendicular2 = Vector3D.CrossProduct(direction, perpendicular1);
        perpendicular2.Normalize();
        
        // 生成圆柱体的顶点
        for (int i = 0; i <= segments; i++)
        {
            double angle = 2 * Math.PI * i / segments;
            var offset = perpendicular1 * Math.Cos(angle) * radius + perpendicular2 * Math.Sin(angle) * radius;
            
            // 添加起点圆上的点
            mesh.Positions.Add(startPoint + offset);
            
            // 添加终点圆上的点
            mesh.Positions.Add(endPoint + offset);
        }
        
        // 生成圆柱体的三角形
        for (int i = 0; i < segments; i++)
        {
            int current = i * 2;
            int next = ((i + 1) % segments) * 2;
            
            // 圆柱体侧面的三角形
            mesh.TriangleIndices.Add(current);
            mesh.TriangleIndices.Add(next);
            mesh.TriangleIndices.Add(current + 1);
            
            mesh.TriangleIndices.Add(next);
            mesh.TriangleIndices.Add(next + 1);
            mesh.TriangleIndices.Add(current + 1);
        }
        
        // 创建材质
        var material = new DiffuseMaterial(new SolidColorBrush(color));
        
        // 返回模型
        return new GeometryModel3D(mesh, material);
    }

    /// <summary>
    /// 创建圆锥体模型
    /// </summary>
    /// <param name="basePoint">圆锥体底面中心点</param>
    /// <param name="direction">圆锥体方向向量</param>
    /// <param name="length">圆锥体长度</param>
    /// <param name="diameter">圆锥体底面直径</param>
    /// <param name="color">圆锥体颜色</param>
    /// <returns>圆锥体模型</returns>
    private static GeometryModel3D CreateCone(
        Point3D basePoint, 
        Vector3D direction, 
        double length, 
        double diameter, 
        Color color)
    {
        ArgumentNullException.ThrowIfNull(basePoint);
        ArgumentNullException.ThrowIfNull(direction);
        // 创建圆锥体的几何体
        var mesh = new MeshGeometry3D();
        
        // 圆锥体的分段数
        int segments = 16;
        double radius = diameter / 2;
        
        // 计算圆锥体的顶点
        var apexPoint = basePoint + direction * length;
        
        // 创建垂直于圆锥体方向的向量
        Vector3D perpendicular1, perpendicular2;
        
        // 如果方向向量接近Y轴，使用Z轴作为参考
        if (Math.Abs(direction.Y) > 0.9)
        {
            perpendicular1 = new Vector3D(1, 0, 0);
        }
        else
        {
            perpendicular1 = new Vector3D(0, 1, 0);
        }
        
        // 计算两个垂直向量
        perpendicular1 = Vector3D.CrossProduct(direction, perpendicular1);
        perpendicular1.Normalize();
        perpendicular2 = Vector3D.CrossProduct(direction, perpendicular1);
        perpendicular2.Normalize();
        
        // 添加圆锥体顶点
        mesh.Positions.Add(apexPoint);
        
        // 生成圆锥体底面的顶点
        for (int i = 0; i <= segments; i++)
        {
            double angle = 2 * Math.PI * i / segments;
            var offset = perpendicular1 * Math.Cos(angle) * radius + perpendicular2 * Math.Sin(angle) * radius;
            mesh.Positions.Add(basePoint + offset);
        }
        
        // 生成圆锥体的三角形
        for (int i = 0; i < segments; i++)
        {
            // 圆锥体侧面的三角形
            mesh.TriangleIndices.Add(0);
            mesh.TriangleIndices.Add(i + 1);
            mesh.TriangleIndices.Add(i + 2);
        }
        
        // 创建材质
        var material = new DiffuseMaterial(new SolidColorBrush(color));
        
        // 返回模型
        return new GeometryModel3D(mesh, material);
    }
    #endregion
}